/**
 * EventServer 的测试用例
 */

#include "../src/EventExecuter.h"
#include "../src/EventList.h"
#include "../src/EventNode.h"
#include "../src/EventObject.h"
#include "arpa/inet.h"
#include "stdio.h"
#include "sys/socket.h"
#include "unistd.h"

static ExecuteType exe_type	     = EXECUTE_TYPE_MODIFY_EVENT_ITEM;
static euint64	   online_id	     = 1742428922;
static euint64	   phone	     = 12345678;
static eint64	   end_time	     = 66778;
static const char *old_password	     = "";
static const char *new_password	     = "";
static const char *password	     = "password";
static const char *user_name	     = "korack";
static const char *group_name	     = "group1+test";
static const char *event_name	     = "test_event2";
static const char *event_describe    = "event1_describe2";
static eint32	   verification_code = 6666;
static euint32	   group_id	     = 5346169;
static euint32	   user_id	     = 0;
static euint32	   event_id	     = 5346169;
static euint8	   global_can_write  = 1;
static euint8	   user_can_write    = 1;
static euint8	   can_join	     = 1;

static EventList *
user_register(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR(phone), EVENT_TYPE_UINT64, NULL);
	event_list_add_data(args, event_string_new(user_name),
			    EVENT_TYPE_STRING, event_object_unref);
	event_list_add_data(args, event_string_new(password), EVENT_TYPE_STRING,
			    event_object_unref);
	return args;
}

static EventList *
user_logon_without_vcode(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR(phone), EVENT_TYPE_UINT64, NULL);
	event_list_add_data(args, event_string_new(password), EVENT_TYPE_STRING,
			    event_object_unref);
	return args;
}

static EventList *
user_logon_with_vcode(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR(phone), EVENT_TYPE_UINT64, NULL);
	event_list_add_data(args, event_string_new(password), EVENT_TYPE_STRING,
			    event_object_unref);
	event_list_add_data(args, EPTR((euint64)verification_code),
			    EVENT_TYPE_INT32, NULL);
	return args;
}

static EventList *
user_modify_password(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, event_string_new(old_password),
			    EVENT_TYPE_STRING, event_object_unref);
	event_list_add_data(args, event_string_new(new_password),
			    EVENT_TYPE_STRING, event_object_unref);
	return args;
}

static EventList *
user_modify_name(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, event_string_new(user_name),
			    EVENT_TYPE_STRING, event_object_unref);
	return args;
}

static EventList *
modify_group_name(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, event_string_new(user_name),
			    EVENT_TYPE_STRING, event_object_unref);
	return args;
}

static EventList *
modify_event_item(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)event_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)end_time), EVENT_TYPE_INT64,
			    NULL);
	event_list_add_data(args, event_string_new(event_name),
			    EVENT_TYPE_STRING, event_object_unref);
	event_list_add_data(args, event_string_new(event_describe),
			    EVENT_TYPE_STRING, event_object_unref);
	return args;
}

static EventList *
modify_group_global_can_write_flag(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)global_can_write),
			    EVENT_TYPE_UINT8, NULL);
	return args;
}

static EventList *
modify_group_user_can_write_flag(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)user_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)user_can_write),
			    EVENT_TYPE_UINT8, NULL);
	return args;
}

static EventList *
modify_group_can_join_flag(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)can_join), EVENT_TYPE_UINT8,
			    NULL);
	return args;
}

static EventList *
create_group(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, event_string_new(group_name),
			    EVENT_TYPE_STRING, event_object_unref);
	event_list_add_data(args, EPTR((euint64)global_can_write),
			    EVENT_TYPE_UINT8, NULL);
	event_list_add_data(args, EPTR((euint64)can_join), EVENT_TYPE_UINT8,
			    NULL);
	return args;
}

static EventList *
create_event_item(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)end_time), EVENT_TYPE_INT64,
			    NULL);
	event_list_add_data(args, event_string_new(event_name),
			    EVENT_TYPE_STRING, event_object_unref);
	event_list_add_data(args, event_string_new(event_describe),
			    EVENT_TYPE_STRING, event_object_unref);
	return args;
}

static EventList *
add_user_to_group(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)user_id), EVENT_TYPE_UINT32,
			    NULL);
	return args;
}

static EventList *
remove_group(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	return args;
}

static EventList *
remove_user_from_group(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)user_id), EVENT_TYPE_UINT32,
			    NULL);
	return args;
}

static EventList *
remove_event_from_group(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	event_list_add_data(args, EPTR((euint64)event_id), EVENT_TYPE_UINT32,
			    NULL);
	return args;
}

static EventList *
user_quit_from_group(void)
{
	EventList *args = event_list_new();
	event_list_add_data(args, EPTR((euint64)group_id), EVENT_TYPE_UINT32,
			    NULL);
	return args;
}

static EventList *
keep_online_state(void)
{
	EventList *args = event_list_new();
	return args;
}

typedef EventList *(*EventFunc)(void);
static EventFunc   exe_func[EXECUTE_TYPE_END] = {
	  NULL, // 0
	  user_register,
	  user_logon_without_vcode,
	  user_logon_with_vcode,
	  user_modify_password,
	  user_modify_name, // 5
	  modify_group_name,
	  modify_event_item,
	  modify_group_global_can_write_flag,
	  modify_group_user_can_write_flag,
	  modify_group_can_join_flag, // 10
	  create_group,
	  create_event_item,
	  add_user_to_group,
	  remove_group,
	  remove_user_from_group, // 15
	  remove_event_from_group,
	  user_quit_from_group,
	  keep_online_state,
};

static EventList *
create_request_list(void)
{
	EventList *list, *args;
	list = event_list_new();
	/* OnlineID */
	event_list_add_data(list, EPTR(online_id), EVENT_TYPE_UINT64, NULL);
	/* ClientRequest Command 服务器指令 */
	event_list_add_data(list, EPTR((euint64)exe_type), EVENT_TYPE_INT32,
			    NULL);
	args = exe_func[exe_type]();
	event_list_add_data(list, args, EVENT_TYPE_LIST, event_object_unref);
	return list;
}

static void
print_list(EventList *list)
{
	euint64	     data;
	ResponseType re_type;
	re_type = (eint32)EN_GET_D(list, euint64);
	printf("操作结果: %s", response_type[re_type]);
	list = EN_GET_NEXT(list, EventList *);
	if (!list)
		return;
	data = EN_GET_D(list, euint64);
	printf("附加数据: %lu\n", data);
}

int
main(void)
{
	EventList *send_list = NULL, *recv_list = NULL;
	EventRaw  *raw_object = NULL;
	epointer   raw_data;
	euint32	   raw_size;
	char	   buffer[1024];
	//
	struct sockaddr_in address;
	//
	int sock, status;
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		return 1;
	}
	address.sin_family = AF_INET;
	address.sin_port   = htons(9611);
	inet_pton(AF_INET, "127.0.0.1", &address.sin_addr);

	send_list = create_request_list();
	event_list_print(send_list);
	raw_object = event_list_export_raw(send_list);
	if (!raw_object)
		goto err;

	event_debug(ServerTest, main, "连接到 127.0.0.1 ......");
	status = connect(sock, (struct sockaddr *)&address, sizeof(address));
	if (status != 0) {
		perror("connect");
		goto err;
	}
	event_debug(ServerTest, main, "连接成功。");
	raw_data = event_raw_get_data(raw_object);
	raw_size = event_raw_get_size(raw_object);

	event_debug(ServerTest, main, "发送消息包 ......");
	status = send(sock, raw_data, (size_t)raw_size, 0);
	if (status != raw_size) {
		perror("send");
		goto err;
	}
	event_object_unref(raw_object);
	event_debug(ServerTest, main, "发送完成，status<%d>, 总共<%u>", status,
		    raw_size);

	event_debug(ServerTest, main, "等待服务器消息 ......");
	status = recv(sock, buffer, 1024, 0);
	if (status == -1) {
		perror("recv");
		goto err;
	} else if (status == 0) {
		printf("接收到空消息。\n");
		goto err;
	} else {
		event_debug(ServerTest, main, "已接收到消息，准备解析 ......");
	}

	recv_list = event_list_new_with_raw(buffer);
	if (!recv_list) {
		printf("无法识别的 EventList 结构。\n");
		goto err;
	} else {
		event_debug(ServerTest, main, "解析成功。");
	}

	print_list(recv_list);

err:
	event_debug(ServerTest, main, "关闭连接。");
	close(sock);
	perror("close");
	event_object_unref(send_list);
	event_object_unref(recv_list);
	return 0;
}
